﻿using System;
using System.Collections.Generic;
using System.Device.Location;
using System.Net;
using System.Text;

namespace ChinaGeo
{
    internal static class QueryAgent
    {
        const string OffsetApi = @"http://api.map.baidu.com/ag/coord/convert?from=0&to=2&x={1}&y={0}";
        readonly private static object asyncRoot = new object();

        private static WebClient wc = new WebClient();
        private static Queue<QueryWraper> queue = new Queue<QueryWraper>();
        static QueryAgent()
        {
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
        }

        private static void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            var wraper = e.UserState as QueryWraper;
            if (wraper == null)
                return;
            if (e.Cancelled || e.Error != null)
            {
                Query(wraper);
            }
            else
            {
                bool? flag = null;
                var latitude = 0.0;
                var longitude = 0.0;
                try
                {
                    var group = e.Result.Split('"');
                    if (group[2] != ":0,")
                    {
                        flag = true;
                    }
                    else
                    {
                        var latitudeBytes = Convert.FromBase64String(group[9]);
                        var longitudeBytes = Convert.FromBase64String(group[5]);
                        latitude = double.Parse(Encoding.UTF8.GetString(latitudeBytes, 0, latitudeBytes.Length));
                        longitude = double.Parse(Encoding.UTF8.GetString(longitudeBytes, 0, longitudeBytes.Length));
                        flag = false;
                    }
                }
                catch { }
                if (flag == true)
                {
                    Query(wraper);
                }
                else if (flag == false)
                {
                    var model = new ChinaGeoModel(wraper.Location.Copy(), new GeoCoordinate(latitude, longitude)) { IsEarthToChina = true };
                    Cache.Update(model.EarthGeo, model.ChinaGeo);
                    if (wraper.Callback != null)
                        wraper.Callback(model);
                    if (model.Effect != null)
                    {
                        model.Effect(model);
                        model.Effect = null;
                    }
                }
            }

            TryQuery();
        }

        public static void Query(GeoCoordinate location, Action<ChinaGeoModel> callback)
        {
            Query(new QueryWraper { Location = location, Callback = callback });
        }

        private static void Query(QueryWraper wraper)
        {
            if (++wraper.Times >= 3)
                return;
            lock (asyncRoot)
                queue.Enqueue(wraper);
            TryQuery();
        }

        private static void TryQuery()
        {
            lock (asyncRoot)
            {
                if (wc.IsBusy || queue.Count == 0)
                    return;
                var wraper = queue.Dequeue();
                wc.DownloadStringAsync(new Uri(string.Format(OffsetApi, wraper.Location.Latitude, wraper.Location.Longitude)), wraper);
            }
        }

        private class QueryWraper
        {
            public GeoCoordinate Location;
            public Action<ChinaGeoModel> Callback;
            public int Times;
        }
    }
}
